using System;
using System.Collections;
using Sedna.Core.Common.Objects.Navigation;
using Sedna.Core.Controller;

namespace Sedna.Core.Security
{
    /// <summary>
    /// Access policy (view & edit) that should be applied to page's controls
    /// </summary>
    public class AccessPolicy : IAccessPolicy
    {
        private IList rolesEnabled;
        private IList rolesVisible;

        private String enabledPath;
        private String visiblePath;
        
        private IAction onEditable;
        private IAction onReadOnly;
        private IAction onUnavailable;
        
        # region Properties

        public IList RolesEnabled
        {
            get { return rolesEnabled; }
            set { rolesEnabled = value; }
        }

        public IList RolesVisible
        {
            get { return rolesVisible; }
            set { rolesVisible = value; }
        }

        /// <summary>
        /// Path to set <b>enabled</b> value
        /// </summary>
        public string EnabledPath
        {
            get { return enabledPath; }
            set { enabledPath = value; }
        }

        /// <summary>
        /// Path to set <b>visible</b> value
        /// </summary>
        public string VisiblePath
        {
            get { return visiblePath; }
            set { visiblePath = value; }
        }

        /// <summary>
        /// Action that will be called if visible = true and enabled = true
        /// </summary>
        public IAction OnEditable
        {
            get { return onEditable; }
            set { onEditable = value; }
        }

        /// <summary>
        /// Action that will be called if visible = true and enabled = false
        /// </summary>
        public IAction OnReadOnly
        {
            get { return onReadOnly; }
            set { onReadOnly = value; }
        }

        /// <summary>
        /// Action that will be called if visible = false
        /// </summary>
        public IAction OnUnavailable
        {
            get { return onUnavailable; }
            set { onUnavailable = value; }
        }

        # endregion

        public virtual void Apply(IPrincipalWrapper principalWrapper, IExecutionContext executionContext)
        {
            bool enabled = IsEnabledForPrincipal(principalWrapper, executionContext);
            bool visible = IsVisibleForPrincipal(principalWrapper, executionContext);
            
            if (!String.IsNullOrEmpty(enabledPath))
                executionContext.SetPropertyValue(enabledPath, enabled);
            
            if (!String.IsNullOrEmpty(visiblePath))
                executionContext.SetPropertyValue(visiblePath, visible);
            
            if (enabled && visible)
            {
                if (onEditable != null)
                    onEditable.Execute(executionContext);
            }
            else if (visible)
            {
                if (onReadOnly != null)
                    onReadOnly.Execute(executionContext);
            }
            else if (onUnavailable != null)
            {
                onUnavailable.Execute(executionContext);
            }                       
        }



        protected virtual bool IsVisibleForPrincipal(IPrincipalWrapper principalWrapper, IExecutionContext executionContext)
        {
            if (principalWrapper == null || rolesVisible == null || rolesVisible.Count == 0)
            {
                return true;
            }

            foreach (string roleName in rolesVisible)
            {
                if (principalWrapper.IsInRole(roleName))
                {
                    return true;
                }
            }

            if (rolesEnabled == null || rolesEnabled.Count == 0)
            {
                return false;
            }

            return IsEnabledForPrincipal(principalWrapper, executionContext);
        }

        protected virtual bool IsEnabledForPrincipal(IPrincipalWrapper principalWrapper, IExecutionContext executionContext)
        {
            if (principalWrapper == null || rolesEnabled == null || rolesEnabled.Count == 0)
            {
                return true;
            }

            foreach (string roleName in rolesEnabled)
            {
                if (principalWrapper.IsInRole(roleName))
                {
                    return true;
                }
            }

            return false;
        }
    }
}
